﻿//-----------------------------------------------------------------------
// <copyright file="Repository.cs" company="ET">
//     Copyright Huirui. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace Huirui.Cavan.Data.Seedwork
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Linq.Expressions;
    using System.Reflection;
    using System.Data;
    using Spring.Data.NHibernate.Generic.Support;
    using NHibernate;
    using NHibernate.Linq;
    using Spring.Data.Generic;
    using Huirui.Cavan.Core.Helper;
    using Huirui.Cavan.Core.Extension;
    using Huirui.Cavan.Core.MyLinq;
    using Huirui.Cavan.Core.MyException;
    using Huirui.Cavan.Domain.Seedwork;
    using Huirui.Cavan.Core.Persistent;

    /// <summary>
    /// Repository基类
    /// </summary>
    /// <typeparam name="T">实体</typeparam>
    public abstract class Repository<T, TSearch> : HibernateDaoSupport, IRepository<T, TSearch>
        where T : class
        where TSearch : class,ISearch
    {
        public AdoTemplate AdoTemplate { get; set; }

        public virtual T Get(object id)
        {
            if (id == null) throw new ArgumentNullException("id");
            return this.HibernateTemplate.Get<T>(id);
        }

        public virtual T Get(ISpecification<T, TSearch> specification)
        {
            return this.Session.Query<T>().FirstOrDefault(specification.Expression);
        }

        public virtual void Save(T model)
        {
            if (model == null) throw new ArgumentNullException("model");
            this.HibernateTemplate.Save(model);
        }

        public virtual void Update(T model)
        {
            if (model == null) throw new ArgumentNullException("model");
            //this.Session.FlushMode = FlushMode.Auto;
            this.HibernateTemplate.Update(model);
            //this.HibernateTemplate.Flush();
        }

        public virtual void SaveOrUpdate(T model)
        {
            if (model == null) throw new ArgumentNullException("model");
            this.HibernateTemplate.SaveOrUpdate(model);
        }

        public virtual void Delete(T model)
        {
            if (model == null) throw new ArgumentNullException("model");
            this.HibernateTemplate.Delete(model);
        }

        public virtual void SubmitChanges()
        {
            this.Session.Flush();
        }

        public virtual IQueryable<T> GetAll()
        {
            return this.Session.Query<T>();
        }

        public virtual IQueryable<T> GetAll(ISpecification<T, TSearch> specification)
        {
            //specification.SearchParam.TotalRowCount = GetCount(specification);
            return this.Session.Query<T>().Where(specification.Expression);
        }

        public virtual long GetCount<T>()
        {
            return this.Session.Query<T>().Count();
        }

        public virtual long GetCount(ISpecification<T, TSearch> specification)
        {
            return this.Session.Query<T>().Count(specification.Expression);
        }

        public IList<T> GetPageList(ISpecification<T, TSearch> specification)
        {
            try
            {
                var source = this.Session.Query<T>().Where(specification.Expression);
                string order = string.Empty;
                if (specification.SearchParams.OrderBy.Count > 0)
                {
                    foreach (string key in specification.SearchParams.OrderBy.Keys)
                    {
                        order = order + key + " " + (specification.SearchParams.OrderBy[key] ? "desc" : "asc") + ",";
                    }
                    order = StringHelper.ClearLastChar(order);
                }
                IQueryable<T> query = source.Skip((specification.SearchParams.CurrentPage - 1) * specification.SearchParams.MaxRowsPerPage).Take(specification.SearchParams.MaxRowsPerPage);
                if (order.IsNotEmpty())
                {
                    query = source.OrderBy(order).Skip((specification.SearchParams.CurrentPage - 1) * specification.SearchParams.MaxRowsPerPage).Take(specification.SearchParams.MaxRowsPerPage);
                }
                return query.ToList<T>();
            }
            catch (DaoException ex)
            {
                this.Log().Fatal(ex);
                throw (new DaoException("数据访问出错: " + ex.Message, ex));
            }
        }

        public virtual IList<T> GetPageList(out long total, ISpecification<T, TSearch> specification)
        {
            total = this.GetCount(specification);
            return this.GetPageList(specification);
        }

        public virtual IList<T> GetPageList(TSearch search, out long total)
        {
            try
            {
                var source = this.Session.Query<T>().Where(search.Sql);
                var sourceTotal = this.Session.Query<T>().Where(search.Sql);
                total = sourceTotal.Count();
                string order = string.Empty;
                if (search.OrderBy.Count > 0)
                {
                    foreach (string key in search.OrderBy.Keys)
                    {
                        order = order + key + " " + (search.OrderBy[key] ? "desc" : "asc") + ",";
                    }
                    order = StringHelper.ClearLastChar(order);
                }
                IQueryable<T> query = source.Skip((search.CurrentPage - 1) * search.MaxRowsPerPage).Take(search.MaxRowsPerPage);
                if (order.IsNotEmpty())
                {
                    query = source.OrderBy(order).Skip((search.CurrentPage - 1) * search.MaxRowsPerPage).Take(search.MaxRowsPerPage);
                }
                return query.ToList<T>();
            }
            catch (DaoException ex)
            {
                this.Log().Fatal(ex);
                throw (new DaoException("数据访问出错: " + ex.Message, ex));
            }
        }

        public void CloseSession()
        {
            if (null != this.Session && this.Session.IsOpen)
            {
                this.Session.Close();
            }
        }
    }
}